#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <vector>
#include <functional>
#include <stdio.h>
#include <queue>
using namespace std;

template <class T>
using fun = function<void(T &)>;

template <class T>
class mypthread
{
public:
    static void *pthread_function(void *formal)
    {
        mypthread<T> *tmp = static_cast<mypthread<T> *>(formal);
        tmp->work();
        return nullptr;
    }

    void work()
    {
        _fun(_data);
    }

    mypthread(string name, fun<T> function, T &data) : _name(name), _run(false), _fun(function), _data(data)
    {
    }

    ~mypthread()
    {
    }

    bool start()
    {
        cout << _name << endl;
        sleep(1);
        int i = pthread_create(&_id, nullptr, pthread_function, this);
        if (i == 0)
        {
            _run = true;
        }
        else
        {
            return false;
        }
        return true;
    }

    void join()
    {
        if (_run)
        {
            pthread_join(_id, nullptr);
        }
    }

    void Detach()
    {
        if (_run)
        {
            pthread_detach(_id);
        }
    }

    void stop()
    {
        _run = false;
    }

private:
    string _name;
    pthread_t _id;
    bool _run;
    fun<T> _fun;
    T& _data;
};

//阻塞队列
template <class T>
class bock_queue
{
public:
    bock_queue(int max):_max(max)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_producer, nullptr);
        pthread_cond_init(&_consumer, nullptr);
    }

    // 生产
    void push(T& data)
    {
        // 放入数据时要保证原子性，加锁
        pthread_mutex_lock(&_mutex);

        
        while (full()) // 满了就阻塞
        {
            //开始堵塞
            pthread_cond_wait(&_producer, &_mutex); // 阻塞时释放锁
        }


        _bock_queue.push(data);
        // 生产完通知消费者
        pthread_cond_signal(&_consumer);

        // 解锁
        pthread_mutex_unlock(&_mutex);
    }

    int size()
    {
        return _bock_queue.size();
    }

    // 消费
    void pop(T* data)
    {
        // 消费数据时要保证原子性，加锁
        pthread_mutex_lock(&_mutex);
        
        //判断空
        while (empty()) // 空了就阻塞
        {
            pthread_cond_wait(&_consumer, &_mutex); // 阻塞时释放锁
        }

        // 开始消费
        *data = _bock_queue.front();
        _bock_queue.pop();
        // 消费完通知生产
        pthread_cond_signal(&_producer);

        // 解锁
        pthread_mutex_unlock(&_mutex);
    }

    ~bock_queue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_producer);
        pthread_cond_destroy(&_consumer);
    }

    bool full()
    {
        return _bock_queue.size() == _max;
    }

    bool empty()
    {
        return _bock_queue.empty();
    }

private:
    queue<T> _bock_queue;    // 阻塞队列
    pthread_cond_t _producer; // 生产者条件信号
    pthread_cond_t _consumer; // 消费者条件信号
    pthread_mutex_t _mutex;   // 锁
    int _max;                // 最大容量
};